/**
 * 
 */
package br.com.skynix.tcmc.service.entidadedominio;

import java.util.Collections;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.primefaces.model.SortOrder;
import org.springframework.stereotype.Repository;

import br.com.skynix.tcmc.base.model.EntidadeAuditavel;
import br.com.skynix.tcmc.base.model.EntidadeDominio;

/**
 * @author mgrb
 * 
 */
@Repository
public class EntidadeDominioDao {

	@PersistenceContext(name = "tcmc-persistence-unit")
	private EntityManager entityManager;

	/**
	 * Insere uma instancia de {@link EntidadeAuditavel} no Banco de dados.
	 * @param entidade instancia de {@link EntidadeAuditavel}.
	 * @return nova chave da entidade.
	 */
	public Long insert(EntidadeDominio entidade) {
		entityManager.persist(entidade);
		return entidade.getId();
	}

	/**
	 * Busca a Entidade pela chave primaria.
	 * @param id Instancia da Chave primaria.
	 * @return Instancia de {@link EntidadeAuditavel}.
	 */
	public EntidadeDominio findByPK(Long id,
			Class<? extends EntidadeDominio> clazz) {
		return entityManager.find(clazz, id);
	}

	/**
	 * Atualiza a instancia de Entidade no banco de dados.
	 * @param entidade instancia de {@link EntidadeAuditavel}.
	 */
	public void update(EntidadeDominio entidade) {
		entityManager.merge(entidade);
	}

	/**
	 * @param entidadeExemplo
	 * @param class1
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<EntidadeDominio> findByExemple(EntidadeDominio entidadeExemplo,
			Class<? extends EntidadeDominio> classePersistente) {
		Example example = Example.create(entidadeExemplo);
		example = example.enableLike(MatchMode.ANYWHERE);
		example = example.ignoreCase();

		Session session = (Session) entityManager.getDelegate();
		Criteria criteria = session.createCriteria(classePersistente);

		criteria.add(example);
		criteria.add(Restrictions.eq("deleted", false));
		return Collections.checkedList(criteria.list(), classePersistente);
	}

	/**
	 * @param modelo
	 * @param first
	 * @param pageSize
	 * @param sortField
	 * @param sortOrder
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<EntidadeDominio> findByExemple(EntidadeDominio modelo,
			int first, int pageSize, String sortField, SortOrder sortOrder) {

		Criteria criteria = createCriteriaByExample(modelo);
		criteria.setFirstResult(first);
		criteria.setMaxResults(pageSize);
		if (StringUtils.isNotBlank(sortField)) {
			if (SortOrder.ASCENDING.equals(sortOrder)) {
				criteria.addOrder(Order.asc(sortField));
			}
			else if (SortOrder.DESCENDING.equals(sortOrder)) {
				criteria.addOrder(Order.desc(sortField));
			}
		}

		return criteria.list();
	}

	/**
	 * @param entidadeExemplo
	 * @return
	 */
	private Criteria createCriteriaByExample(EntidadeDominio entidadeExemplo) {
		Example example = Example.create(entidadeExemplo);
		example = example.enableLike(MatchMode.ANYWHERE);
		example = example.ignoreCase();

		Criteria criteria = createCriteria(entidadeExemplo.getClass());
		criteria.add(example);
		criteria.add(Restrictions.eq("deleted", false));
		return criteria;
	}

	/**
	 * @return
	 */
	protected Criteria createCriteria(Class<? extends EntidadeAuditavel> clazz) {
		Session session = (Session) entityManager.getDelegate();
		Criteria criteria = session.createCriteria(clazz);
		return criteria;
	}

	/**
	 * @param modelo
	 * @return
	 */
	public int rowCount(EntidadeDominio modelo) {
		Criteria criteria = createCriteriaByExample(modelo);
		criteria.setProjection(Projections.rowCount());
		Object rowCount = criteria.uniqueResult();
		return rowCount == null ? 0 : (Integer) rowCount;
	}
}
